-- Rudimentary Logic Client & Server Implementation --

-- Client --

	-- Shortcuts for database applications
remote.insert .fact :- remote.if (insert .fact) #
remote.delete .fact :- remote.if (delete .fact) #
remote.search .fact :- remote.grab .fact (search .fact) #
remote.searchOnce .fact :- remote.grabOnce .fact (search .fact) #

	-- Attention! Use 'once' version if no backtracking is being planned.
	-- For those predicates named without 'once,' the socket is only closed
	-- after final invocation failure; i.e. you must elaborate all
remote.query .query :- remote.grab .query .query #
remote.queryOnce .query :- remote.grabOnce .query .query ! #

	-- Only yes/no without bindings (supposedly faster)
remote.if .query :- remote.grabOnce Y .query ! #

	-- Specified a variable to bind
remote.grab .v .q :- doRequest (.v | .q) . #
remote.grabOnce .v .q :- doRequest (.v | .q) .socket, stream.close .socket ! #

doRequest (.var | .query) .stream :-
	temporary .stream,
	getHost .server .port,
	concat "nc -q0 " .server " " .port .command,
	once (
		stream.popen .stream .command,
		stream.dump .stream (.var | .query),
		stream.nl .stream,
		stream.flush .stream;
		connectionFault
	),
	grabResultLine .stream .str,
	parse .str .var #

getHost .server .port :- remote.server .server .port ! #
getHost "localhost" 5151 #

grabResultLine .stream .result :-
	temporary .tag, untilEndOfQuery .tag .stream .result #
grabResultLine .stream . :-
	stream.close .stream, fail #

	-- Ugly and costly, but perhaps the only way since there is no full cut
untilEndOfQuery .tag .stream .line :-
	not (get .tag EXIT),
	once (
		once (
			stream.line .stream .line;
			connectionFault
		),
		not (.line = "%FF")
	;
		set .tag EXIT, fail
	) #
untilEndOfQuery .tag .stream .line :-
	not (get .tag EXIT),
	untilEndOfQuery .tag .stream .line #
untilEndOfQuery .tag . . :-
	unset .tag, fail #

connectionFault :- raise "Remote connection failure" #


-- Stub Generation --

define.remote .pred :- assert (.pred :- remote.query .pred) #

define.remoteOnce .pred :- assert (.pred :- remote.queryOnce .pred) #
